/**
 * Lkx-1.1.2 | 2017 MIT License
 * 官方文档：http://lkx2217.cn
 * 更新时间：2017.11.15
 * 模块化前端管理框架
 * */

(function(win) {

    "use strict";

    //共同获取方法
    //返回基础的document对象
    //基础的querySelector获取方法
    //创建对象的createElement方法
    var native = {
            doc: function() { return document; },
            query: function(dom) { return native.doc().querySelector(dom); },
            create: function(dom) { return native.doc().createElement(dom); }
        },

        //公共字段
        //记录使用use所生成的方法
        //记录空字段以及以及官方模块名
        //返回当前接入的设备状态
        field = {
            fun: [],
            empty: /^[ ]*$/,
            loading: null,
            module: ['Popup', 'Verify', 'Zoom'],
            device: navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i) ? 'mobile' : 'pc',

            //注册文件
            //判断在配置文件下的文件是否引入
            //如果引入将不在对同名文件进行引入
            registerCss: [],
            registerJs: []
        },

        //共同使用方法
        //包括判断数据类型是否正常
        //删增class操作
        common = {

            //判断所需字段的数据类型是否符合规范
            str: function(text) { return (typeof text === 'string' && !field.empty.test(text)) ? true : false; },
            num: function(parameter) { return typeof parameter === 'number' ? true : false; },
            boo: function(parameter) { return typeof parameter === 'boolean' ? true : false; },
            fun: function(parameter) { return typeof parameter === 'function' ? true : false; },
            obj: function(parameter) {
                var hasObj;
                for (var o in parameter) {
                    hasObj = true;
                    break;
                }
                return (typeof parameter === 'object' && hasObj) ? true : false;
            },

            //查找dom对象的class值
            hasClass: function(dom, cls) {
                cls = cls || '';
                if (cls.replace(/\s/g, '').length === 0) {
                    return false;
                }
                return new RegExp(' ' + cls + ' ').test(' ' + dom.className + ' ');
            },

            //增加doc对象的class值
            addClass: function(dom, cls) {
                if (!common.hasClass(dom, cls)) {
                    dom.className = dom.className === '' ? cls : dom.className + ' ' + cls;
                }
            },

            //删除doc对象的class值
            removeClass: function(dom, cls) {
                if (common.hasClass(dom, cls)) {
                    var newClass = ' ' + dom.className.replace(/[\t\r\n]/g, '') + ' ';
                    while (newClass.indexOf(' ' + cls + ' ') >= 0) {
                        newClass = newClass.replace(' ' + cls + ' ', ' ');
                    }
                    dom.className = newClass.replace(/^\s+|\s+$/g, '');
                }
            },

            //获取引入Lkx的所在目录
            //所有Lkx依赖文件以及模块均以此方法返回为基础进行增加
            getPath: function() {
                var docScript = native.doc().scripts,
                    LkxPath = docScript[docScript.length - 1].src;
                return LkxPath.substring(0, LkxPath.lastIndexOf('/') + 1);
            }(),

            //获取当前地址栏地址
            //包括返回主机地址以及绝对浏览器地址路径
            path: function() {
                var path = native.doc().location.href,
                    pathName = native.doc().location.pathname,
                    pos = path.indexOf(pathName),
                    host = path.substring(0, pos),
                    address = path.substring(0, path.lastIndexOf('/')),
                    projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);

                return {
                    'host': host + projectName,
                    'address': address
                };
            },

            //创建meta标签
            //设置页面放大倍数
            //功能为可以在pc端和移动端之间自由切换
            createMeta: function() {
                var createMeta = native.create('meta');
                createMeta.name = 'viewport';
                createMeta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';

                native.query('head').appendChild(createMeta);
            },

            //通过判断滚动条位置在页面右下角增加置顶按钮
            topBtn: function() {

                var createTopBtn = native.create('div'),
                    scrollTopVar,
                    clientHeight = native.doc().documentElement.clientHeight,
                    timer;

                //根据设备修改相应的样式
                common.addClass(createTopBtn, 'Lkx-icon');
                common.addClass(createTopBtn, 'Lkx-icon-top');
                common.addClass(createTopBtn, 'Lkx-topBtn');

                common.addClass(createTopBtn, field.device === 'pc' ? 'Lkx-topBtn-pc' : 'Lkx-topBtn-mobile');
                native.query('body').appendChild(createTopBtn);

                //对滚动条进行监听
                win.onscroll = function() {
                    scrollTopVar = native.doc().documentElement.scrollTop || native.doc().body.scrollTop;
                    if (scrollTopVar >= (clientHeight / 2)) {

                        createTopBtn.style.display = 'block';

                        clearTimeout(timer);
                        timer = setTimeout(function() {
                            common.addClass(createTopBtn, 'Lkx-topBtn-show');
                            common.removeClass(createTopBtn, 'Lkx-topBtn-hide');
                        });
                    } else {
                        common.addClass(createTopBtn, 'Lkx-topBtn-hide');
                        common.removeClass(createTopBtn, 'Lkx-topBtn-show');

                        clearTimeout(timer);
                        timer = setTimeout(function() {
                            createTopBtn.style.display = 'none';
                        }, 100);
                    }
                };

                //对topBtn进行事件绑定*
                createTopBtn.onclick = function() {
                    common.scroll(0);
                };
            },

            //滚动条置顶
            scroll: function(num) {
                setTimeout(function() {
                    var scrollFnTop = native.doc().documentElement.scrollTop || native.doc().body.scrollTop,
                        step = 30,
                        dist = Math.floor((num - scrollFnTop) / step),
                        nextY = scrollFnTop + dist;
                    if (nextY > num) {
                        win.scrollTo(0, nextY);
                        common.scroll(num);
                    } else {
                        win.scrollTo(0, num);
                    }
                });
            }
        },

        //初始化加载页面时在显示一层loading动画
        //此方法用于在模块化引入css时遮盖未加载样式的结构
        loading = function() {

            var animation = native.create('div');
            field.loading = native.create('div');

            for (var i = 0; i < 5; i++) {
                animation.appendChild(native.create('div'));
            }

            common.addClass(field.loading, 'Lkx-loading');
            common.addClass(animation, 'Lkx-loading-animation');
            common.addClass(native.query('html'), 'Lkx-noScrollBar');

            field.loading.appendChild(animation);
            native.query('html').appendChild(field.loading);

            //初始化修改loading的样式
            field.loading.style.cssText = 'width:100%;height:100%;position:fixed;left:0;top:0;background:#fff';
        }();

    //配置文件加载
    //基础分流以及判断
    //通过Lkx.use进行调用
    var Load = function(Lkx) {

        this.Lkx = Lkx;

        this.definition();
        this.initCreate();
    };

    Load.prototype = {

        //初始化定义成员变量
        definition: function() {

            this.loadLine = 0;
            this.path = common.getPath;
            this.hostAddress = common.getPath;

            //获取文件
            //获取配置文件下的对应文件
            this.css = [];
            this.js = [];
            this.module = [];
        },

        //初始化加载Lkx的相关依赖文件
        //包括配置文件以及css样式文件
        initCreate: function() {
            this.createLink(this.path, 'css/Lkx.css');
            this.createLink(this.path, 'css/Lkx-icon.css');
            this.createScript(this.path, 'Config.js', 'init');
        },

        //文件中转站
        //主要用于处理当前js文件加载完毕之后的去向
        //direction 从何处所来
        returnLoad: function(direction) {

            //初始化加载完配置文件所来
            //进行配置文件读取获取config变量
            if (direction === 'init') {
                this.read();
            }

            //配置文件下project加载完毕所来
            //进行加载新的配置文件变量
            //不再执行当前配置文件下的file字段
            else if (direction === 'project') {
                this.config = eval(this.var);
                this.file();
            }

            //file字段下的js或module加载完毕之后所来
            //判断是否再次加载以及下一步去向
            else {

                this.loadLine++;

                if (this.loadLine < this.scriptLength) {
                    direction.indexOf('Js') >= 0 ? this.createJs(direction) : this.createModule(direction);
                } else {

                    this.loadLine = 0;

                    //循环所来的方向
                    switch (direction) {

                        //全局js文件加载完毕所来
                        case 'allJs':
                            common.obj(this.module['allModule']) ? this.createModule('allModule') : this.single() ? this.singleJump() : this.end();
                            break;

                            //全局module文件加载完毕所来
                        case 'allModule':
                            this.single() ? this.singleJump() : this.end();
                            break;

                            //局部js文件加载完毕所来
                        case 'singleJs':
                            common.obj(this.module['singleModule']) ? this.createModule('singleModule') : this.end();
                            break;

                            //局部module文件加载完毕所来
                        case 'singleModule':
                            this.end();
                            break;
                    }
                }
            }
        },

        //读取配置文件
        //对配置文件进行类型判断以及字段判断
        read: function() {
            this.config = Config;
            common.obj(this.config) ? common.obj(this.config.project) ? this.shunt(true) : this.shunt(false) : this.end();
        },

        //进行加载文件分流
        //分流setting字段以及project字段
        //根据setting字段的内容进行不同的走向
        //根据project判断来进行新配置文件加载
        shunt: function(project) {

            //对setting下所有参数进行赋值
            this.setting();

            //进行服务器地址或本地路径字段替换
            if (this.hostAddress.indexOf('host') >= 0) {
                this.hostAddress = this.hostAddress.replace(/host/, common.path().host);
            } else if (this.hostAddress.indexOf('path') >= 0) {
                this.hostAddress = this.hostAddress.replace(/path/, common.path().address);
            }

            //读取配置文件下meta字段
            if (this.meta && field.device === 'mobile') { common.createMeta(); }

            //判断配置文件是否存在topBtnData
            if (this.topBtn) { common.topBtn(); }

            //是否存在外链项目文件查询
            project ? this.project() ? this.createScript(this.hostAddress, this.src, 'project') : this.file() : this.file();
        },

        //配置文件下project字段
        //链接外部配置文件
        //如果存在将进行读取，与默认配置文件下的file不进行共存
        project: function() {

            for (var p = 0; p < this.config.project.length; p++) {
                this.name = this.config.project[p].name;

                if (this.Lkx.project === this.name && this.Lkx.project && common.str(this.name) && common.str(this.src) && common.str(this.var)) {
                    this.src = this.config.project[p].src;
                    this.var = this.config.project[p].var;
                    return true;
                } else if (p === this.config.project.length - 1) {
                    return false;
                }
            }
        },

        //配置文件下setting赋值
        //setting不受project字段影响，因此它是全局性的
        //只存在于默认的配置文件内
        setting: function(that) {

            var setting = common.obj(this.config.setting) ? this.config.setting : {};

            this.meta = common.boo(setting.meta) ? setting.meta : true;
            this.topBtn = common.boo(setting.topBtn) ? setting.topBtn : true;
            this.randomNum = common.boo(setting.randomNum) ? setting.randomNum : false;
            this.hostAddress = common.str(setting.hostAddress) ? setting.hostAddress : 'path/';
        },

        //进行配置文件路径读取
        //如果默认配置文件下存在project字段
        //那么此处读取的将会是新配置文件下的内容
        file: function() {

            if (common.obj(this.config.file)) {

                //全局配置文件字段判断
                if (common.obj(this.config.file.allPage)) {

                    this.css['all'] = this.config.file.allPage.css;
                    this.js['allJs'] = this.config.file.allPage.js;
                    this.module['allModule'] = this.config.file.allPage.module;

                    //判断是否存在全局css文件
                    //存在进行创建
                    if (common.obj(this.css['all'])) { this.createCss('all'); }

                    //判断是否存在全局js文件
                    //存在进行创建
                    if (common.obj(this.js['allJs'])) {
                        this.createJs('allJs');
                    }

                    //判断是否存在全局module
                    //若是不存在将进入局部文件判断
                    //存在进行创建
                    else {
                        common.obj(this.module['allModule']) ? this.createModule('allModule') : this.single() ? this.singleJump() : this.end();
                    }
                }

                //若是不存在全局将直接进入局部文件判断
                else if (common.obj(this.config.file.singlePage) && this.single()) {
                    this.singleJump();
                } else {
                    this.end();
                }
            } else {
                this.end();
            }
        },

        //局部配置文件分流
        //创建所属局部文件下css
        //创建所属文件下js
        singleJump: function() {

            //创建创建css
            if (common.obj(this.css['single'])) { this.createCss('single'); }

            //局部js与module判断与创建
            common.obj(this.js['singleJs']) ? this.createJs('singleJs') : common.obj(this.module['singleModule']) ? this.createModule('singleModule') : this.end();
        },

        //判断局部配置文件是否存在
        //存在进行PageName匹配
        //成功返回true，并对所属PageName下文件进行存储
        single: function() {

            var htmlPageName = this.Lkx.page,
                singlePage,
                singlePageName;

            for (var s in this.config.file.singlePage) {
                singlePage = this.config.file.singlePage[s];
                singlePageName = singlePage.pageName;

                if (common.str(htmlPageName) && common.str(singlePageName) && htmlPageName === singlePageName) {

                    this.PageName = singlePageName;

                    this.css['single'] = singlePage.css;
                    this.js['singleJs'] = singlePage.js;
                    this.module['singleModule'] = singlePage.module;

                    return true;
                }
            }
        },

        //配置文件css加载以及注册
        //因为没有依赖关系所有将会循环直接加载和注册
        createCss: function(direction) {
            for (var c = 0; c < this.css[direction].length; c++) {
                if (common.str(this.css[direction][c]) && field.registerCss.indexOf(this.css[direction][c]) < 0) {
                    field.registerCss.push(this.css[direction][c]);
                    this.createLink(this.hostAddress, this.css[direction][c]);
                }
            }
        },

        //配置文件js加载
        //获取当前类下js文件的长度以及js文件的路径
        createJs: function(direction) {
            this.scriptLength = this.js[direction].length;
            this.register(this.js[direction][this.loadLine], direction);
        },

        //配置文件module加载
        //判断是否启用useAll字段或是官方module字段
        createModule: function(direction) {
            for (var m = 0; m < this.module[direction].length; m++) {
                if (this.module[direction][m].indexOf('useAll') >= 0) {
                    this.scriptLength = field.module.length;
                    this.register(field.module[this.loadLine], direction);
                    break;
                } else {
                    if (m === this.module[direction].length - 1) {
                        this.scriptLength = this.module[direction].length;
                        this.register(this.module[direction][this.loadLine], direction);
                    }
                }
            }
        },

        //js文件注册
        //同时注册js文件和module文件
        //同一文件名只进行注册一次和加载一次
        register: function(jsFile, direction) {

            if (common.str(jsFile) && field.registerJs.indexOf(jsFile) < 0) {
                field.registerJs.push(jsFile);
                direction.indexOf('Js') >= 0 ?
                    this.createScript(this.hostAddress, jsFile, direction) :
                    this.createScript(this.path, 'module/' + jsFile + '.js', direction);
            } else {
                this.returnLoad(direction);
            }
        },

        //初始化Lkx依赖css创建
        //配置文件下的css文件创建
        //所有css文件的创建均走入此方法
        createLink: function(path, address) {

            var link = native.create('link');

            link.media = 'all';
            link.type = 'text/css';
            link.rel = 'stylesheet';
            link.href = path + (this.randomNum ? address + '?' + Math.random() : address);

            native.query('head').appendChild(link);
        },

        //初始化Lkx依赖js创建
        //配置文件下的js文件创建
        //所有js文件的创建均走入此方法
        createScript: function(path, address, state) {

            var script = native.create('script'),
                that = this;

            script.type = 'text/javascript';
            script.async = 'async';
            script.charset = 'utf-8';
            script.src = path + (that.randomNum ? address + '?' + Math.random() : address);

            native.query('body').appendChild(script);

            script.addEventListener('load', function() {
                native.query('body').removeChild(script);
                that.returnLoad(state);
            });
        },

        //结束方法
        //无论是新配置文件还是默认配置文件
        //当所有文件加载完毕时进入
        end: function() {

            //初始化加载页面时在显示一层loading动画
            //进行loading动画移除，展示其页面
            common.addClass(field.loading, 'Lkx-loading-hide');
            common.removeClass(native.query('html'), 'Lkx-noScrollBar');
            setTimeout(function() {
                native.query('html').removeChild(field.loading);
            }, 150);

            //当配置文件全部加载完毕时进行调用
            //所有代码写入此内，将可以使用配置文件加载的所有文件
            for (var i = 0; i < field.fun.length; i++) {
                field.fun[i]();
            }
        }
    };

    //向外暴露的Lkx构造函数
    //通过此方法展开原型链实现模块化引入
    var Lkx = function() {
        this.version = 'Lkx-1.1.2';
        this.time = '2017.11.15';
    };

    Lkx.fn = Lkx.prototype;

    //初始化定义配置
    //此配置与配置文件里的setting是分开独立互不干预的
    //配置所属的页面名以及项目名
    //配置初始化时是否加载loading动画
    Lkx.fn.define = function(parameter) {

        this.page = common.str(parameter.page) ? parameter.page : false;
        this.project = common.str(parameter.project) ? parameter.project : false;

        //返回Load
        //进行配置文件加载
        return this.load();
    };

    //所有方法总入口
    //启动方法读取配置文件
    //加载配置文件，进行模块化引入
    Lkx.fn.use = function(fun) {

        //传入的funciton
        //当配置文件全部加载完毕时进行调用
        field.fun.push(common.fun(fun) ? fun : function() {});

        //返回Load
        //进行配置文件加载
        return this.load();
    };

    //返回经过计算的相关信息
    //包括当前服务器名，页面绝对路径，设备类型以及版本编号
    Lkx.fn.info = function() {
        return {
            'host': common.path().host,
            'path': common.path().address,
            'device': field.device,
            'version': this.version + ' / ' + this.time
        };
    };

    //进行页面配置文件方法调用
    //当然也可以直接使用此方法进行调用
    //但是将不会获取到use信息以及define信息
    Lkx.fn.load = function() {
        var that = this;
        win.onload = function() { new Load(that); };
    };

    win.Lkx = new Lkx();

})(window);